package com.lambert.gingko.watermark.strategy.impl;

import com.lambert.gingko.watermark.annotation.FileProcessor;
import com.lambert.gingko.watermark.enums.ContentLocation;
import com.lambert.gingko.watermark.enums.FileType;
import com.lambert.gingko.watermark.model.PositionParam;
import com.lambert.gingko.watermark.model.WatermarkConfig;
import com.lambert.gingko.watermark.strategy.AbstWatermarkProcessor;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
import org.apache.pdfbox.util.Matrix;
import org.springframework.core.io.ClassPathResource;

import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

/**
 * PDF 水印处理器增强版
 * 支持倾斜角度、位置偏移和不同内容区域的水印添加
 */
@FileProcessor(FileType.PDF)
@Slf4j
public class PdfWatermarkProcessor extends AbstWatermarkProcessor {

    /**
     * 处理PDF文件并添加水印
     */
    @Override
    protected void doProcess(InputStream is,File outputFile , String extension, WatermarkConfig config) throws Exception {

        try (PDDocument document = PDDocument.load(is)) {
            // 3. 添加水印
            addWatermarkToPdf(document, config);
            // 4. 保存处理后的PDF
            document.save(outputFile);
            log.info("PDF水印添加成功");
        }
    }

    /**
     * 为PDF文档添加水印
     */
    private void addWatermarkToPdf(PDDocument document, WatermarkConfig config) throws IOException {
        // 加载字体
        PDFont font = loadFont(document, config.getFont());

        // 为每一页添加水印
        for (PDPage page : document.getPages()) {
            //addTiledWatermark(document, page, config, font);
            addWatermarkToPage(document, page, config, font);
        }
    }

    /**
     * 为单个PDF页面添加水印
     */
    private void addWatermarkToPage(PDDocument document, PDPage page, WatermarkConfig config, PDFont font) throws IOException {
        PDRectangle pageSize = page.getMediaBox();
        float pageWidth = pageSize.getWidth();
        float pageHeight = pageSize.getHeight();

        // 根据内容位置调整页面区域
        PDRectangle contentArea = getContentArea(page, pageSize, config.getContentLocation());

        try (PDPageContentStream contentStream = new PDPageContentStream(
                document, page, PDPageContentStream.AppendMode.APPEND, true, true)) {

            // 设置透明度
            PDExtendedGraphicsState graphicsState = new PDExtendedGraphicsState();
            graphicsState.setNonStrokingAlphaConstant(config.getOpacity());
            graphicsState.setStrokingAlphaConstant(config.getOpacity());
            graphicsState.setAlphaSourceFlag(true);
            contentStream.setGraphicsStateParameters(graphicsState);

            // 计算水印位置
            PositionParam positionParam = config.getPositionParam();
            positionParam.setEnclosingWidth((int) contentArea.getWidth());
            positionParam.setEnclosingHeight((int) contentArea.getHeight());

            // 计算文本尺寸
            float textWidth = font.getStringWidth(config.getText()) / 1000 * config.getFont().getSize();
            float textHeight = config.getFont().getSize();
            positionParam.setWidth((int) textWidth);
            positionParam.setHeight((int) textHeight);

            // 计算基础位置（基于内容区域）
            Point basePoint = config.getPosition().calculate(positionParam);

            // 应用偏移量
            float x = basePoint.x + contentArea.getLowerLeftX() ;
            float y = pageHeight - (basePoint.y + contentArea.getLowerLeftY());

            // 处理倾斜角度
            if (config.getAngle() != 0) {
                addRotatedTextWatermark(contentStream, config.getText(), font,
                        config.getFont().getSize(), config.getColor(),
                        x, y, config.getAngle());
            } else {
                addTextWatermark(contentStream, config.getText(), font,
                        config.getFont().getSize(), config.getColor(), x, y);
            }
        }
    }

    /**
     * 根据内容位置获取相应的区域
     */
    private PDRectangle getContentArea(PDPage page, PDRectangle pageSize, ContentLocation contentLocation) {
        // 默认使用整个页面
        PDRectangle contentArea = pageSize;

        // 这里可以根据contentLocation返回不同的区域
        // 例如，可以计算页眉、页脚或正文区域
        // 以下是一个简单示例：
        switch (contentLocation) {
            case HEADER:
                // 页眉区域（页面顶部20%）
                return new PDRectangle(
                        pageSize.getLowerLeftX(),
                        pageSize.getUpperRightY() - pageSize.getHeight() * 0.2f,
                        pageSize.getWidth(),
                        pageSize.getHeight() * 0.2f
                );
            case FOOTER:
                // 页脚区域（页面底部15%）
                return new PDRectangle(
                        pageSize.getLowerLeftX(),
                        pageSize.getLowerLeftY(),
                        pageSize.getWidth(),
                        pageSize.getHeight() * 0.15f
                );
            case CONTENT:
            default:
                // 正文区域（去除页眉页脚的中间部分）
                return new PDRectangle(
                        pageSize.getLowerLeftX(),
                        pageSize.getLowerLeftY() + pageSize.getHeight() * 0.15f,
                        pageSize.getWidth(),
                        pageSize.getHeight() * 0.7f
                );
        }
    }

    /**
     * 添加文本水印（无旋转）
     */
    private void addTextWatermark(PDPageContentStream contentStream, String text,
                                  PDFont font, float fontSize, Color color,
                                  float x, float y) throws IOException {
        contentStream.beginText();
        contentStream.setFont(font, fontSize);
        contentStream.setNonStrokingColor(color.getRed(), color.getGreen(), color.getBlue());
        contentStream.newLineAtOffset(x, y);
        contentStream.showText(text);
        contentStream.endText();
    }

    /**
     * 添加旋转文本水印
     */
    private void addRotatedTextWatermark(PDPageContentStream contentStream, String text,
                                         PDFont font, float fontSize, Color color,
                                         float x, float y, double angle) throws IOException {
        // 将角度转换为弧度
        double radians = Math.toRadians(angle);

        // 创建旋转矩阵
        Matrix matrix = Matrix.getRotateInstance(radians, x, y);

        contentStream.beginText();
        contentStream.setFont(font, fontSize);
        contentStream.setNonStrokingColor(color.getRed(), color.getGreen(), color.getBlue());
        contentStream.setTextMatrix(matrix);
        contentStream.newLineAtOffset(0, 0); // 位置已通过矩阵设置
        contentStream.showText(text);
        contentStream.endText();
    }

    /**
     * 添加平铺水印（覆盖整个页面）
     */
    private void addTiledWatermark(PDDocument document, PDPage page, WatermarkConfig config, PDFont font) throws IOException {
        PDRectangle pageSize = page.getMediaBox();
        float pageWidth = pageSize.getWidth();
        float pageHeight = pageSize.getHeight();

        try (PDPageContentStream contentStream = new PDPageContentStream(
                document, page, PDPageContentStream.AppendMode.APPEND, true, true)) {

            // 设置透明度
            PDExtendedGraphicsState graphicsState = new PDExtendedGraphicsState();
            graphicsState.setNonStrokingAlphaConstant(config.getOpacity());
            graphicsState.setStrokingAlphaConstant(config.getOpacity());
            graphicsState.setAlphaSourceFlag(true);
            contentStream.setGraphicsStateParameters(graphicsState);

            // 设置字体和颜色
            contentStream.setFont(font, config.getFont().getSize());
            Color color = config.getColor();
            contentStream.setNonStrokingColor(color.getRed(), color.getGreen(), color.getBlue());

            // 计算文本宽度和高度
            float textWidth = font.getStringWidth(config.getText()) / 1000 * config.getFont().getSize();
            float textHeight = config.getFont().getSize();

            // 计算平铺的行列数
            int cols = (int) (pageWidth / (textWidth * 2));
            int rows = (int) (pageHeight / (textHeight * 2));

            // 添加平铺水印
            for (int i = 0; i < rows; i++) {
                for (int j = 0; j < cols; j++) {
                    float x = j * textWidth * 2;
                    float y = pageHeight - (i * textHeight * 2);

                    if (config.getAngle() != 0) {
                        addRotatedTextWatermark(contentStream, config.getText(), font,
                                config.getFont().getSize(), color,
                                x, y, config.getAngle());
                    } else {
                        addTextWatermark(contentStream, config.getText(), font,
                                config.getFont().getSize(), color, x, y);
                    }
                }
            }
        }
    }

    /**
     * 加载PDF字体
     */
    private PDFont loadFont(PDDocument document, Font font) throws IOException {
        try {
            // 尝试加载系统字体
            return PDType0Font.load(document, new File(font.getName()));
        } catch (Exception e) {
            try {
                // 尝试从资源目录加载字体
                String fontPath = "com/lambert/gingko/watermark/fonts/SimHei.ttf";
                InputStream fontStream = new ClassPathResource(fontPath).getInputStream();
                if (fontStream != null) {
                    return PDType0Font.load(document, fontStream);
                }
            } catch (Exception ex) {
                log.warn("无法加载指定字体: {}, 使用默认字体", font.getName(), ex);
            }

            // 使用默认字体
            try {
                return PDType0Font.load(document, getClass().getResourceAsStream("/com/lambert/gingko/watermark/fonts/SimSun.ttf"));
            } catch (Exception e2) {
                // 最后回退到内置字体
                return PDType0Font.load(document, getClass().getResourceAsStream("/com/lambert/gingko/watermark/fonts/arial.ttf"));
            }
        }
    }

    @Override
    public FileType getSupportedType() {
        return FileType.PDF;
    }
}